<?php

// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// * Copyright 2014 The Herosphp Authors. All rights reserved.
// * Use of this source code is governed by a MIT-style license
// * that can be found in the LICENSE file.
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

declare(strict_types=1);

namespace herosphp\plugin\storage\handler;

use herosphp\exception\HeroException;
use herosphp\plugin\storage\core\Error;
use herosphp\utils\StringUtil;
use Qiniu\Auth;
use Qiniu\Config;
use Qiniu\Storage\BucketManager;
use Qiniu\Storage\UploadManager;

/**
 * 七牛云 OSS 文件上传 Handler 实现
 * --------------------------------------------------
 * @author RockYang<yangjian102621@gmail.com>
 */
class QiniuFileSaveHandler implements FileHandler
{
    protected static array $_config = [];

    protected static Auth $_auth;

    public function __construct(array $config)
    {
        if (
            empty($config) ||
            !isset($config['access_key']) ||
            !isset($config['secret_key']) ||
            !isset($config['bucket'])
        ) {
            throw new HeroException('Invalid upload configs');
        }

        // create Authentication
        static::$_auth = new Auth($config['access_key'], $config['secret_key']);

        if (!str_ends_with($config['domain'], '/')) {
            $config['domain'] = $config['domain'] . '/';
        }

        static::$_config = $config;
    }

    // upload binary file
    public function save(string $srcFile, string $filename): array
    {
        $uploadMgr = new UploadManager();
        $token = static::$_auth->uploadToken(static::$_config['bucket']);
        [$ret, $err] = $uploadMgr->putFile($token, $filename, $srcFile, null, 'application/octet-stream', true, null, 'v2');
        if ($err !== null) {
            return [null, new Error(21, $err->message())];
        }

        return [static::$_config['domain'] . $ret['key'], null];
    }

    // upload base64 encode image
    public function saveBase64($data, string $filename): array
    {
        // 上传文件服务地址
        // 华东空间：upload.qiniu.com
        // 华北空间: upload-z1.qiniu.com
        // 华南空间: upload-z2.qiniu.com
        // 北美空间: upload-na0.qiniu.com

        $zone = "upload-z2.qiniu.com";
        if (!empty(static::$_config['zone'])) {
            $zone = static::$_config['zone'];
        }
        $url = "http://{$zone}/putb64/-1/key/".base64_encode($filename);
        $token = static::$_auth->uploadToken(static::$_config['bucket']);
        $headers = [
            'Content-Type:image/png',
            'Authorization:UpToken ' . $token,
        ];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        $ret = curl_exec($ch);
        curl_close($ch);

        $ret = StringUtil::jsonDecode($ret);
        if (isset($ret['error']) && $ret['error'] !== null) {
            return [null, new Error(22, $ret['error'])];
        }

        return [static::$_config['domain'] . $ret['key'], null];
    }

    // fetch file list
    public function list(int $page, int $pageNo): array
    {
        throw new HeroException('Not implemented.');
    }

    // delete the specified file
    public function delete(string $filename): array
    {
        $config = new Config();
        $bucketManager = new BucketManager(static::$_auth, $config);
        [$ret, $err] = $bucketManager->delete(static::$_config['bucket'], $filename);
        if ($err != null) {
            return [null, new Error(21, $err->message())];
        }
        return [$ret, null];
    }
}
